9  循环语句 股价涨跌幅提醒

9.1 引言循环在批量金融数据处理中的价值

金融市场产生海量的时间序列数据——股价、成交量、收益率等。循环结构使我们能够高效地处理这些重复数据,自动执行重复性任务,是构建金融分析系统的核心工具。

理论背景:迭代与递归

从计算理论来看,循环实现了迭代(Iteration)模式: - 迭代: 通过重复执行相同操作处理数据集合 - 递归: 函数调用自身解决问题 - 对比: 循环通常更高效,递归更优雅

在金融数据处理中,迭代更为常见,因为: - 金融数据天然具有顺序性(时间序列) - 内存消耗可控(不需要递归栈) - 更容易理解和调试

9.2 For循环基础

9.2.1 语法结构

for循环用于遍历序列(列表、元组、字符串等)或其他可迭代对象。

语法: for item in iterable:

列表 9.1
# =============================================================================
# 题目:For循环的基本遍历操作
# =============================================================================
# 本代码演示for循环的四种基本用法:
# 1. 遍历列表 - 最常见的场景,处理股票列表
# 2. 遍历字符串 - 处理股票代码
# 3. 遍历范围 - 生成索引或重复操作
# 4. 遍历字典 - 处理键值对数据
# for循环是金融数据处理中最常用的结构,必须熟练掌握

# ==================== 示例1:遍历列表 ====================
stocks = ['中信证券', '国泰君安', '海通证券']  # 定义券商股票列表

for stock in stocks:  # 依次取出列表中的每个股票名称
    print(f"分析股票: {stock}")  # 输出当前处理的股票
# for循环会自动遍历列表,不需要手动管理索引

# ==================== 示例2:遍历字符串 ====================
code = "600519.SH"  # 贵州茅台的股票代码
for char in code:  # 依次取出字符串中的每个字符
    print(char)  # 输出当前字符
# 可以用于解析股票代码的各个部分

# ==================== 示例3:遍历范围 ====================
for i in range(5):  # 生成0到4的整数序列
    print(f"第{i+1}次迭代")  # 输出迭代次数(从1开始计数)
# range(5)生成序列[0,1,2,3,4],不包括5

# ==================== 示例4:遍历字典 ====================
stock_info = {'name': '中信证券', 'code': '600030.SH', 'price': 24.78}  # 股票信息字典
for key in stock_info:  # 依次取出字典的键
    print(f"{key}: {stock_info[key]}")  # 输出键和对应的值
# 默认遍历字典的键,通过键访问值

9.2.2 range()函数

range()生成整数序列,是循环中最常用的工具。

语法: range(start, stop, step)

列表 9.2
# =============================================================================
# 题目:使用range函数生成各种整数序列
# =============================================================================
# 本代码演示range函数的四种常用模式:
# 1. 指定结束值 - 最简单的用法
# 2. 指定起始和结束值 - 生成特定区间
# 3. 指定步长 - 生成等差序列
# 4. 负步长 - 倒序遍历
# range函数在金融计算中用于生成索引、时间范围等

# ==================== 用法1:指定结束值(不包含) ====================
for i in range(5):  # 生成0,1,2,3,4
    print(f"i = {i}")  # 输出: 0,1,2,3,4
# range(stop)生成0到stop-1的整数

# ==================== 用法2:指定起始和结束值 ====================
for year in range(2020, 2025):  # 生成2020到2024
    print(f"年份: {year}")  # 输出: 2020,2021,2022,2023,2024
# range(start,stop)生成start到stop-1的整数
# 常用于遍历特定年份的财务数据

# ==================== 用法3:指定步长 ====================
for i in range(0, 10, 2):  # 生成0,2,4,6,8
    print(f"偶数: {i}")  # 输出偶数序列
# range(start,stop,step)以步长step生成序列
# 常用于跳过某些数据或按固定间隔采样

# ==================== 用法4:负步长(倒序) ====================
for i in range(10, 0, -1):  # 生成10,9,8,...,1
    print(f"倒计时: {i}")  # 输出递减序列
# 负步长用于倒序遍历,如从最新到最旧的数据

# ==================== 金融应用:生成工作日 ====================
import numpy as np  # 导入NumPy库
dates = np.arange('2024-01-01', '2024-01-06', dtype='datetime64[D]')  # 生成日期序列
print("\n2024年1月前5个工作日:")  # 输出标题
for date in dates:  # 遍历日期序列
    print(f"  {date}")  # 输出每个日期
# np.arange生成日期范围,常用于时间序列分析

9.3 While循环

while循环在条件为True时重复执行,适用于不确定迭代次数的情况。

语法: while condition:

列表 9.3
# =============================================================================
# 题目:While循环模拟价格监控过程
# =============================================================================
# 本代码演示while循环的实际应用:
# 1. 简单计数 - 基础用法,理解循环机制
# 2. 价格监控模拟 - 模拟股票价格达到目标价的过程
# while循环适合处理不确定次数的重复任务
# 在金融交易中用于监控实时价格、等待特定条件触发

# ==================== 示例1:简单计数 ====================
count = 0  # 初始化计数器
while count < 5:  # 当计数器小于5时持续循环
    print(f"计数: {count}")  # 输出当前计数值
    count += 1  # 重要:更新循环变量,避免无限循环
# 循环执行5次后,count变为5,条件不再满足,退出循环

# ==================== 示例2:模拟价格监控 ====================
print("\n价格监控模拟:")  # 输出标题
price = 18.00  # 初始价格
target = 20.00  # 目标价格
days = 0  # 天数计数器

while price < target:  # 当价格低于目标价时持续监控
    # 模拟价格变化
    price += 0.50  # 每天价格上涨0.50元
    days += 1  # 天数加1
    print(f"第{days}天, 价格: {price:.2f}元")  # 输出每日价格

    # 安全措施:避免无限循环
    if days > 100:  # 如果监控超过100天
        print("达到最大监控天数")  # 输出警告
        break  # 强制退出循环
# break语句立即终止循环,不管条件是否满足

print(f"\n达到目标价20元, 耗时{days}天")  # 输出结果
# 实际应用中,while循环常用于实时监控市场数据

重要警告: while循环容易陷入无限循环,必须确保: 1. 循环条件最终会变为False 2. 循环体内有更新条件的语句 3. 添加安全措施(如最大迭代次数)

9.4 循环控制语句

9.4.1 break跳出循环

列表 9.4
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
r_list=[0.0192,-0.0001,0.006,0.0074,-0.0127,-0.0067,0.0095,-0.0095]  # 定义每日涨跌幅列表
for i in r_list:  # 逐日遍历涨跌幅数据
    if i<-0.01:  # 判断当日跌幅是否超过1%
        break  # 发现跌幅超限,立即跳出循环
print('涨跌幅数据',i)  # 输出触发跌幅预警时的涨跌幅值

代码深度解析:

  1. break的执行逻辑:
    • 立即跳出最内层循环
    • 不执行循环体剩余代码
    • 继续执行循环后的语句
  2. 金融应用场景:
    • 止损触发: 价格触及止损位立即平仓
    • 异常检测: 发现异常数据停止处理
    • 目标达成: 达到盈利目标退出
  3. 变量作用域:
    • 循环变量在循环外仍然可访问
    • i保持循环中的最后一个值
    • 这是Python的特性(不是bug)

9.4.2 continue跳过当前迭代

列表 9.5
# =============================================================================
# 题目:使用continue语句跳过特定数据
# =============================================================================
# 本代码演示continue语句的使用:
# 场景:只处理正收益的交易日,跳过负收益日
# continue语句用于过滤不需要处理的数据
# 在金融分析中常用于筛选特定条件的数据

# ==================== 定义收益率数据 ====================
returns = [0.0192, -0.0001, 0.006, 0.0074, -0.0127, 0.0095]
# 6个交易日的收益率数据

# ==================== 只处理正收益交易日 ====================
print("正收益交易日:")  # 输出标题

count = 0  # 正收益日计数器
for r in returns:  # 遍历每个收益率
    # 跳过负收益
    if r < 0:  # 如果收益率为负
        continue  # 跳过本次迭代剩余代码,直接进入下一次迭代
    # continue之后的代码不会被执行

    count += 1  # 正收益日计数加1
    print(f"  第{count}个正收益日: {r:.2%}")  # 输出正收益率
# :.2%格式化为百分比,保留2位小数

print(f"\n总计正收益日: {count}天")  # 输出正收益日总数
# 输出: 4天(跳过了2个负收益日)
# continue只跳过当前迭代,循环继续执行

9.4.3 break vs continue

关键字 作用 后续代码 循环继续
break 跳出循环 不执行,从循环后继续
continue 跳过本次 不执行,从下次迭代继续

9.5 循环中的else子句

Python的循环可以带else子句,在循环正常结束时执行(未被break中断)。

列表 9.6
# =============================================================================
# 题目:循环else子句的两种执行情况
# =============================================================================
# 本代码演示循环else子句的使用:
# 1. 循环正常结束 - 执行else子句
# 2. 循环被break中断 - 不执行else子句
# else子句用于区分"正常结束"和"中断退出"两种情况
# 在金融数据验证中非常有用

# ==================== 场景1:循环正常结束 ====================
prices = [10, 11, 12, 13, 14]  # 价格列表(都低于20)

for price in prices:  # 遍历价格
    if price > 20:  # 检查是否有价格超过20
        print("发现高价股票")  # 发现高价
        break  # 跳出循环
else:  # 循环未被break中断,执行else
    print("所有股票价格都在合理范围")  # 所有价格都合理
# 输出: "所有股票价格都在合理范围"

print("\n" + "="*50 + "\n")  # 输出分隔线

# ==================== 场景2:循环被break中断 ====================
prices2 = [10, 11, 25, 13, 14]  # 价格列表(包含25)

for price in prices2:  # 遍历价格
    if price > 20:  # 检查是否有价格超过20
        print("发现高价股票")  # 发现高价(25)
        break  # 跳出循环
else:  # 由于break被执行,else不会执行
    print("所有股票价格都在合理范围")
# 输出: "发现高价股票" (else子句未执行)

金融应用: 验证所有数据是否符合条件

列表 9.7
# =============================================================================
# 题目:使用循环else验证数据完整性
# =============================================================================
# 本代码演示如何使用循环else进行数据验证:
# 场景:验证所有价格是否为正数
# 如果发现任何异常价格(<=0),立即中断并提示
# 如果所有价格都正常,输出验证通过的提示

# ==================== 定义价格数据 ====================
prices = [24.78, 20.15, 14.03, 22.41, 16.17]  # 股票价格列表
# 所有价格都是正数

# ==================== 验证所有价格是否为正数 ====================
for price in prices:  # 遍历每个价格
    if price <= 0:  # 检查是否有非正价格
        print(f"发现异常价格: {price}")  # 输出异常价格
        break  # 发现异常,立即中断
else:  # 循环正常结束(未发现异常)
    print("✓ 所有价格数据有效")  # 输出验证通过信息
# 输出: "✓ 所有价格数据有效"
# 这种模式在金融数据清洗中非常常用

9.6 实战案例股价涨跌幅监控

列表 9.8
# =============================================================================
# 题目:股价涨跌幅实时监控系统
# =============================================================================
# 本代码实现一个完整的股价监控系统:
# 1. 模拟一周的股价数据
# 2. 逐日计算涨跌幅
# 3. 根据涨跌幅判断市场状态
# 4. 触发预警时自动停止监控
# 这个系统综合运用了for循环、if条件判断、break语句等核心概念
# 是实际量化交易系统的基础框架

# ==================== 导入NumPy库 ====================
import numpy as np  # 导入用于生成随机数和数值计算

# ==================== 模拟一周的股价数据 ====================
np.random.seed(42)  # 设置随机种子,确保结果可重现
base_price = 20.0  # 起始价格
price_changes = np.random.randn(5) * 0.5  # 生成5日价格变化(标准差0.5)
prices = base_price + np.cumsum(price_changes)  # 累加变化得到价格序列
# np.cumsum计算累积和,模拟价格的随机游走

# ==================== 输出系统标题 ====================
print("=" * 60)  # 输出分隔线
print("股价涨跌幅监控系统")  # 输出系统名称
print("=" * 60)  # 输出分隔线

# ==================== 设定预警阈值 ====================
alert_threshold = -0.01  # 跌幅超过-1%触发警报

# ==================== 逐日监控股价 ====================
for i, price in enumerate(prices, 1):  # 遍历价格序列,i从1开始
    # 计算涨跌幅
    if i == 1:  # 第一天没有前一日数据
        daily_return = 0  # 涨跌幅设为0
    else:  # 其他天数
        daily_return = (price - prices[i-2]) / prices[i-2]  # 计算收益率
    # prices[i-2]是前一日价格(因为enumerate从1开始,i-2才是正确的索引)

    # 转换为百分比
    return_pct = daily_return * 100  # 转换为百分比形式

    # 判断市场状态
    if daily_return < alert_threshold:  # 跌幅超过阈值
        status = "⚠️ 警告"  # 风险警告状态
        action = "考虑减仓"  # 建议减仓
    elif daily_return > 0.01:  # 涨幅超过1%
        status = "✓ 上涨"  # 上涨状态
        action = "继续持有"  # 建议持有
    else:  # 正常波动范围
        status = "正常"  # 正常状态
        action = "观望"  # 建议观望

    # 输出每日监控报告
    print(f"\n{i}天:")  # 输出天数
    print(f"  收盘价: {price:.2f}元")  # 输出收盘价
    print(f"  涨跌幅: {return_pct:+.2f}%")  # 输出涨跌幅(+表示正号)
    print(f"  状态: {status}")  # 输出状态
    print(f"  建议: {action}")  # 输出操作建议

    # 检查是否需要停止监控
    if daily_return < alert_threshold:  # 如果触发预警
        print("\n" + "=" * 60)  # 输出分隔线
        print("触发风险预警,系统暂停监控")  # 输出预警信息
        print("=" * 60)  # 输出分隔线
        break  # 立即停止监控
else:  # 循环正常结束(未触发break)
    # 循环正常结束(未触发警报)
    print("\n" + "=" * 60)  # 输出分隔线
    print("一周监控结束,市场表现平稳")  # 输出总结信息
    print("=" * 60)  # 输出分隔线
# for-else结构:正常结束时执行else,break中断时不执行

9.7 嵌套循环

在处理二维数据(如多只股票多日收益)时,需要使用嵌套循环。

列表 9.9
# =============================================================================
# 题目:嵌套循环统计每日上涨股票数量
# =============================================================================
# 本代码演示嵌套循环的使用:
# 场景:3只股票,5个交易日的收益率数据
# 任务:统计每个交易日有多少只股票上涨
# 嵌套循环用于处理二维数据结构(外层遍历天数,内层遍历股票)
# 这是金融数据分析中的常见模式

# ==================== 定义收益率数据 ====================
returns = [
    [0.01, 0.02, -0.01, 0.03, 0.02],  # 股票A的5日收益率
    [0.02, -0.01, 0.03, 0.01, -0.02],  # 股票B的5日收益率
    [-0.01, 0.03, 0.02, -0.02, 0.01]   # 股票C的5日收益率
]
# 这是一个3行5列的二维列表(矩阵)

stock_names = ['股票A', '股票B', '股票C']  # 股票名称列表

# ==================== 统计每日正收益股票 ====================
print("每日正收益股票统计:\n")  # 输出标题

for day in range(5):  # 外层循环:遍历5个交易日
    positive_count = 0  # 正收益股票计数器
    positive_stocks = []  # 正收益股票名称列表

    for stock_idx in range(3):  # 内层循环:遍历3只股票
        ret = returns[stock_idx][day]  # 获取第stock_idx只股票在第day天的收益率
        # returns[stock_idx]是第stock_idx只股票的所有收益率
        # [day]取出该股票在第day天的收益率

        if ret > 0:  # 如果收益率为正
            positive_count += 1  # 计数器加1
            positive_stocks.append(stock_names[stock_idx])  # 添加股票名称

    # 输出当日统计结果
    print(f"第{day+1}天: {positive_count}只股票上涨")  # 输出上涨股票数量
    print(f"  上涨股票: {', '.join(positive_stocks)}")  # 输出上涨股票名称
    # ', '.join()将列表元素用逗号连接成字符串

性能提示: 嵌套循环时间复杂度为O(n×m),数据量大时应考虑使用NumPy向量化操作。

9.8 循环性能优化

列表 9.10
# =============================================================================
# 题目:不同循环方法的性能对比测试
# =============================================================================
# 本代码演示四种数组相加方法的性能差异:
# 1. Python for循环 - 最慢,但最易懂
# 2. 列表推导 - 较快,更Pythonic
# 3. zip+列表推导 - 更Pythonic,代码更清晰
# 4. NumPy向量化 - 最快,推荐用于大数据
# 性能差异在大数据集上非常明显,NumPy可快数百倍
# 在量化交易中,性能优化直接影响策略回测速度

# ==================== 导入时间库 ====================
import time  # 用于计时

# ==================== 生成大数据集 ====================
n = 100000  # 数据规模:10万个元素
list1 = list(range(n))  # 生成列表[0,1,2,...,99999]
list2 = list(range(n))  # 生成相同的列表

# ==================== 方法1:Python for循环(慢) ====================
start = time.time()  # 记录开始时间
result_loop = []  # 存储结果
for i in range(n):  # 遍历所有元素
    result_loop.append(list1[i] + list2[i])  # 相加并添加到结果列表
loop_time = time.time() - start  # 计算耗时
# for循环最慢,因为每次迭代都有Python解释器开销

# ==================== 方法2:列表推导(较快) ====================
start = time.time()  # 记录开始时间
result_listcomp = [list1[i] + list2[i] for i in range(n)]  # 列表推导
listcomp_time = time.time() - start  # 计算耗时
# 列表推导比for循环快,因为内部优化

# ==================== 方法3:zip+列表推导(更Pythonic) ====================
start = time.time()  # 记录开始时间
result_zip = [a + b for a, b in zip(list1, list2)]  # 使用zip配对
zip_time = time.time() - start  # 计算耗时
# zip函数将两个列表的元素配对,代码更清晰

# ==================== 方法4:NumPy向量化(最快) ====================
import numpy as np  # 导入NumPy
arr1 = np.array(list1)  # 转换为NumPy数组
arr2 = np.array(list2)  # 转换为NumPy数组
start = time.time()  # 记录开始时间
result_numpy = arr1 + arr2  # 直接相加(向量化操作)
numpy_time = time.time() - start  # 计算耗时
# NumPy使用C语言实现向量化操作,速度极快

# ==================== 输出性能对比结果 ====================
print(f"Python循环: {loop_time:.4f}秒")  # 输出循环耗时
print(f"列表推导: {listcomp_time:.4f}秒")  # 输出列表推导耗时
print(f"zip方法: {zip_time:.4f}秒")  # 输出zip方法耗时
print(f"NumPy向量化: {numpy_time:.4f}秒")  # 输出NumPy耗时
print(f"\n最快方法比最慢快 {loop_time/numpy_time:.1f}倍")  # 输出性能倍数
# 在大数据集上,NumPy通常比纯Python循环快100-1000倍
# 这就是为什么量化交易必须使用NumPy/Pandas的原因